package com.xb.cloud.shopping.service.impl;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.xb.cloud.common.JsonUtils;
import com.xb.cloud.common.util.SecurityDigestUtils;
import com.xb.cloud.common.util.StringUtils;
import com.xb.cloud.gateway.client.ReturnCodes;
import com.xb.cloud.gateway.client.ReturnUtils;
import com.xb.cloud.gateway.client.RtnInfo;
import com.xb.cloud.order.service.client.PaymentFlowService;
import com.xb.cloud.order.service.client.PaymentService;
import com.xb.cloud.order.service.client.bo.PaymentFlowBo;
import com.xb.cloud.service.client.ServiceReturnInfo;
import com.xb.cloud.service.client.ServiceReturnUtils;
import com.xb.cloud.shopping.model.PaymentConfig;
import com.xb.cloud.shopping.service.PaymentDelegateService;
import com.xb.cloud.shopping.service.PaymentUtils;
import com.xb.cloud.shopping.service.client.vo.PaymentRequestVo;
import com.xb.cloud.shopping.service.client.vo.PaymentShopInfo;

@Service
public class PaymentDelegateServiceImpl implements PaymentDelegateService {
	private static final Logger LOGGER = LoggerFactory.getLogger(PaymentDelegateServiceImpl.class);

	@Resource
	PaymentFlowService paymentFlowService;

	@Resource
	PaymentService paymentService;

	private RtnInfo invokePaymentApi(TreeMap<String, String> datamap, String urlPath) {
		return null;
	}

	@Override
	public RtnInfo payOrder(PaymentRequestVo requestVo, String openId, String openKey, String outNo, String pmtTag,
			String pmtName, String ordName, Integer originalAmount, Integer discountAmount, Integer ignoreAmount,
			Integer tradeAmount, String remark, String tag, String notifyUrl, String jumpUrl) {
		try {

			TreeMap<String, String> datamap = new TreeMap<String, String>(); // data参数的map
			datamap.put("out_no", outNo);
			datamap.put("pmt_tag", pmtTag);
			datamap.put("pmt_name", pmtName);
			datamap.put("ord_name", ordName);
			datamap.put("original_amount", String.valueOf(originalAmount));
			datamap.put("discount_amount", String.valueOf(discountAmount));
			datamap.put("ignore_amount", String.valueOf(ignoreAmount));
			datamap.put("trade_amount", String.valueOf(tradeAmount));
			datamap.put("remark", remark);
			datamap.put("tag", tag);
			datamap.put("jump_url", jumpUrl);
			datamap.put("notify_url", notifyUrl);

			// 获取加密后的请求参数
			TreeMap<String, String> postmap = PaymentUtils.handleSign(datamap, openId, openKey);

			// 发送下单请求
			String rspStr = PaymentUtils.handlePost(postmap, PaymentConfig.PAYORDER);
			LOGGER.info("支付下单返回：{}", unicode2String(rspStr));

			Map<String, String> responseMap = Collections.emptyMap();
			if (StringUtils.isNotBlank(rspStr)) {
				responseMap = JsonUtils.parseToMap(rspStr);
			}
			String dataStr = responseMap.get("data");

			if (StringUtils.isNotBlank(rspStr) && (dataStr != null)) {
				if (PaymentUtils.verifySign(responseMap, openKey)) {
					// 验签成功，解密返回的data数据
					String respData = SecurityDigestUtils.AESDecrypt(dataStr.toString(), openKey);
					LOGGER.info("支付下单响应data内容 {}", respData);

					Map<String, String> requestMap = new HashMap<>();
					requestMap.putAll(postmap);
					requestMap.put("dataContent", JsonUtils.beanToJson(datamap));
					// 将解密后的数据加入返回数据
					responseMap.put("dataContent", respData);

					JSONObject jsonObject = JSONObject.parseObject(respData);
					String ordNo = jsonObject.getString("ord_no");
					String tradeQrcode = jsonObject.getString("trade_qrcode");
					String jsapiPayUrl = jsonObject.getString("jsapi_pay_url");

					PaymentFlowBo paymentFlowBo = new PaymentFlowBo();
					paymentFlowBo.setCompanyId(requestVo.getCompanyId());
					paymentFlowBo.setShopId(requestVo.getShopId());
					paymentFlowBo.setSoId(requestVo.getOrderId());
					paymentFlowBo.setOutNo(outNo);
					paymentFlowBo.setPaymentCode(ordNo);
					paymentFlowBo.setPaymentTag(pmtTag);
					paymentFlowBo.setPaymentName(pmtName);
					paymentFlowBo.setPaymentAmount(BigDecimal.valueOf(tradeAmount * 1.0 / 100));
					paymentFlowBo.setPaymentRequestContent(JsonUtils.beanToJson(requestMap));
					paymentFlowBo.setPaymentResponseContent(JsonUtils.beanToJson(responseMap));
					paymentFlowBo.setCreateUserId(requestVo.getCurrentUserId());

					ServiceReturnInfo returnInfo = paymentFlowService.createPaymentFlow(paymentFlowBo);
					if (ServiceReturnUtils.isSuccess(returnInfo)) {
						Map<String, String> resultData = new HashMap<>();
						resultData.put("tradeQrcode", tradeQrcode);
						resultData.put("jsapiPayUrl", jsapiPayUrl);
						return ReturnUtils.success(resultData);
					}

					return ReturnUtils.error(ReturnCodes.PAYMENT_FLOW_CREATE_ERROR);
				} else {
					LOGGER.info("支付下单返回验签失败：{}", rspStr);
					return ReturnUtils.error(ReturnCodes.PAYMENT_RETURN_VERIFY_ERROR);
				}
			} else {
				LOGGER.info("==========支付下单没有返回data数据==========");
				return ReturnUtils.error(ReturnCodes.PAYMENT_RETURN_EMPTY_DATA);
			}
		} catch (Exception e) {
			LOGGER.info("支付下单请求失败", e);
			return ReturnUtils.error(ReturnCodes.PAYMENT_REQUEST_ERROR);
		}
	}

	@Override
	public RtnInfo getPayList(String openId, String openKey) {
		String pmtType = "0,1,2,3";
		try {
			// 固定参数
			TreeMap<String, String> datamap = new TreeMap<String, String>();// data参数的map
			datamap.put("pmt_type", pmtType);

			TreeMap<String, String> postmap = PaymentUtils.handleSign(datamap, openId, openKey);
			String rspStr = PaymentUtils.handlePost(postmap, PaymentConfig.PAYLIST);
			LOGGER.info("支付下单返回：{}", unicode2String(rspStr));

			Map<String, String> responseMap = Collections.emptyMap();
			if (StringUtils.isNotBlank(rspStr)) {
				responseMap = JsonUtils.parseToMap(rspStr);
			}

			Object dataStr = responseMap.get("data");

			if (!rspStr.isEmpty() || (dataStr != null)) {
				if (PaymentUtils.verifySign(responseMap, openKey)) { // 验签成功
					String respData = SecurityDigestUtils.AESDecrypt(dataStr.toString(), openKey);
					LOGGER.info("=================响应data内容= " + unicode2String(respData));
					return ReturnUtils.success(respData);
				} else {
					LOGGER.info("支付下单返回验签失败：{}", rspStr);
					return ReturnUtils.error(ReturnCodes.PAYMENT_RETURN_VERIFY_ERROR);
				}
			} else {
				LOGGER.info("==========支付下单没有返回data数据==========");
				return ReturnUtils.error(ReturnCodes.PAYMENT_RETURN_EMPTY_DATA);
			}
		} catch (Exception e) {
			return ReturnUtils.error(null);
		}

	}

	@Override
	public RtnInfo checkPaymentNotify(Map<String, String> params) {
		LOGGER.info("支付回调信息：", JsonUtils.beanToJson(params));

		String ordNo = params.get("ord_no");
		String outNo = params.get("out_no");
		String status = params.get("status");

		PaymentFlowBo paymentFlowBo = new PaymentFlowBo();
		paymentFlowBo.setPaymentCode(ordNo);
		paymentFlowBo.setOutNo(outNo);

		ServiceReturnInfo returnInfo = paymentFlowService.getPaymentFlow(paymentFlowBo);
		if (ServiceReturnUtils.isSuccess(returnInfo) && returnInfo.getData() != null) {
			paymentFlowBo = (PaymentFlowBo) returnInfo.getData();
			Long shopId = paymentFlowBo.getShopId();
			Long soId = paymentFlowBo.getSoId();

			if (paymentFlowBo.getPaymentStatus() != null) {
				// 状态未更新
				String openKey = "";
				PaymentRequestVo requestVo = new PaymentRequestVo();
				requestVo.setShopId(shopId);
				returnInfo = paymentService.getShopPaymentInfo(requestVo);
				if (ServiceReturnUtils.isSuccess(returnInfo) && returnInfo.getData() != null) {
					PaymentShopInfo shopInfo = (PaymentShopInfo) returnInfo.getData();
					openKey = shopInfo.getOpenKey();
				}

				if (StringUtils.isNotBlank(openKey) && PaymentUtils.verifySign(params, openKey)) {
					// 更新支付流水表状态
					paymentFlowBo.setPaymentStatus(Integer.valueOf(status));

					// 调用接口完成订单支付操作：更新支付流水状态，更新订单状态
					returnInfo = paymentService.completePayment(paymentFlowBo);
					if (ServiceReturnUtils.isSuccess(returnInfo)) {
						return ReturnUtils.success();
					}

				} else {
					return ReturnUtils.error(ReturnCodes.PAYMENT_RETURN_VERIFY_ERROR);
				}
			} else {
				LOGGER.error("支付回调对应的支付流水信息的状态已经被修改，直接返回通知方成功。orderId：{}, outNo：{}", soId, outNo);
				return ReturnUtils.success();
			}
		} else {
			LOGGER.error("支付回调没有找到对应的支付流水信息， outNo：{}", outNo);
		}

		return ReturnUtils.error(null);
	}

	public static String unicode2String(String unicode) {
		StringBuilder sb = new StringBuilder();
		int i = -1;
		int pos = 0;

		while ((i = unicode.indexOf("\\u", pos)) != -1) {
			sb.append(unicode.substring(pos, i));
			if (i + 5 < unicode.length()) {
				pos = i + 6;
				sb.append((char) Integer.parseInt(unicode.substring(i + 2, i + 6), 16));
			}
		}
		if (pos < unicode.length()) {
			sb.append(unicode.substring(pos, unicode.length()));
		}
		return sb.toString();
	}
}
